#include "serial_port.h"

SerialImpl::SerialImpl(const std::string path, int rate):
    serial_name_(path),
    serial_rate_(rate)
{
    serial_ = std::make_unique<serial::Serial>();
    rx_call_back_param_ = nullptr;
    is_open_ = false;
}

SerialImpl::~SerialImpl()
{
    stop();
}

bool SerialImpl::openSerial()
{
    try {
        //设置串口属性，并打开串口
        serial_->setPort(serial_name_);
        serial_->setBaudrate(serial_rate_);
        serial_->setFlowcontrol(serial::flowcontrol_t::flowcontrol_none);
        serial_->setParity(serial::parity_t::parity_none);
        serial_->setStopbits(serial::stopbits_t::stopbits_one);
        serial_->setBytesize(serial::bytesize_t::eightbits);
        serial::Timeout timeout = serial::Timeout::simpleTimeout(1000);
        serial_->setTimeout(timeout);
        serial_->open();
    } catch (serial::IOException &e) {
        std::cout << "open serial" << " ERROR: " << e.what() << std::endl;
        return false;
    }

    //检测串口是否已经打开，并给出提示信息data
    if (serial_->isOpen()) {
        std::cout << "chassis serial port initialized success" << std::endl;
        return true;
    }
    is_open_ = true;
    return false;
}

bool SerialImpl::reopenSerial()
{
    serial_->close();
    is_open_ = false;
    return openSerial();
}

bool SerialImpl::closeSerial()
{
    if(is_open_)
        serial_->close();
}

int SerialImpl::sendData(uint8_t* data, size_t len)
{
    if(serial_->isOpen()){
        size_t ret = serial_->write(data, len);
        if(ret == len)
            return ret;
        else
            return -2;
    }
    std::cout << "serial port isn't open" << std::endl;
    return -1;
}

void SerialImpl::start()
{
    process_flag_ = true;
    process_thr_.reset(new std::thread(std::bind(&SerialImpl::readData, this)));
}

void SerialImpl::stop()
{
    process_flag_ = false;
    if(process_thr_ && process_thr_->joinable()){
        process_thr_->join();
        process_thr_ = nullptr;
    }

    
    if(serial_){
        closeSerial();
        serial_.reset();
    } 
}

void SerialImpl::readData()
{
    serial_->flush();
    while (process_flag_)
    {
        if(is_open_){
            if(!serial_->isOpen()){
                std::cout << "serial port reopen" << std::endl;
                std::this_thread::sleep_for(std::chrono::seconds(3));
                reopenSerial();
                continue;
            }
                
            if(serial_->waitReadable()){
                uint8_t buf[1024];
                memset(buf, 0, 1024);
                size_t rx_n = serial_->read(buf, sizeof(buf));
                //todozc
                if(rx_n > 0 && rx_call_back_){
                    rx_call_back_(rx_call_back_param_, buf, rx_n);
                }
            }
            
        }else{
            
            std::cout << "serial port don't open" << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(3));
        }
    }
    
}

